package com.starlinkdt.common.storage.impl;

import com.obs.services.ObsClient;
import com.obs.services.model.HttpMethodEnum;
import com.obs.services.model.ObjectMetadata;
import com.obs.services.model.ObsObject;
import com.obs.services.model.TemporarySignatureRequest;
import com.obs.services.model.TemporarySignatureResponse;
import com.starlinkdt.common.storage.StorageInterface;
import com.starlinkdt.common.storage.config.HuaweiCloudObsConfig;
import org.apache.poi.util.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

/**
 * 华为云对象存储
 *
 * @author system
 */
@Component
public class HuaweiCloudObsImpl implements StorageInterface {
    @Autowired
    private HuaweiCloudObsConfig huaweiCloudObsConfig;

    /**
     * 创建OBS实例
     *
     * @return HuaweiCloudObs
     */
    private ObsClient generateClient() {
        return new ObsClient(huaweiCloudObsConfig.getAccessKeyId(), huaweiCloudObsConfig.getAccessKeySecret(), huaweiCloudObsConfig.getEndpoint());
    }

    /**
     * 关闭OBSClient
     *
     * @param obsClient OBS实例
     */
    private void close(ObsClient obsClient) {
        if (obsClient != null) {
            try {
                obsClient.close();
            } catch (IOException ignored) { }
        }
    }

    /**
     * 获取STS临时令牌
     *
     * @return Map
     */
    @Override
    public Map<String, Object> genStsToken() {
        Map<String, Object> obsMap = new HashMap<>(1);

        obsMap.put("securityToken", null);
        obsMap.put("accessKeyId", huaweiCloudObsConfig.getAccessKeyId());
        obsMap.put("accessKeySecret", huaweiCloudObsConfig.getAccessKeySecret());
        obsMap.put("endpoint", huaweiCloudObsConfig.getEndpoint());
        obsMap.put("bucketName", huaweiCloudObsConfig.getBucketName());

        return obsMap;
    }

    /**
     * 上传Byte数组
     *
     * @param objectName 对象路径及名称
     * @param objectContent byte数组
     */
    @Override
    public void putObjectByte(String objectName, byte[] objectContent) throws IOException {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        try (InputStream inputStream = new ByteArrayInputStream(objectContent)) {
            // 上传Byte数组
            obsClient.putObject(huaweiCloudObsConfig.getBucketName(), objectName, inputStream);
        } finally {
            close(obsClient);
        }
    }

    /**
     * 上传网络流
     *
     * @param objectName 对象路径及名称
     * @param fileUrl 待上传的网络文件地址
     */
    @Override
    public void putObjectUrl(String objectName, String fileUrl) throws IOException {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        try (InputStream inputStream = new URL(fileUrl).openStream()) {
            obsClient.putObject(huaweiCloudObsConfig.getBucketName(), objectName, inputStream);
        } finally {
            close(obsClient);
        }
    }

    /**
     * 上传文件流
     *
     * @param objectName 对象路径及名称
     * @param filePath 待上传的本地文件路径,需要指定到具体的文件名
     */
    @Override
    public void putObjectFile(String objectName, String filePath) throws IOException {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
            obsClient.putObject(huaweiCloudObsConfig.getBucketName(), objectName, inputStream);
        } finally {
            close(obsClient);
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param objectName 对象路径及名称
     * @return boolean
     */
    @Override
    public boolean existObject(String objectName) {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        try {
            // 获取对象属性，包括对象长度，对象MIME类型，对象自定义元数据等信息
            ObjectMetadata metadata = obsClient.getObjectMetadata(huaweiCloudObsConfig.getBucketName(), objectName);
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            close(obsClient);
        }
    }

    /**
     * 获取签名URL
     *
     * @param objectName 对象路径及名称
     * @return String
     */
    @Override
    public String getObjectSignUrl(String objectName) {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        try {
            // 设置签名URL过期时间为3600秒（1小时）
            long expireSeconds = huaweiCloudObsConfig.getDurationSeconds();

            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireSeconds);
            request.setBucketName(huaweiCloudObsConfig.getBucketName());
            request.setObjectKey(objectName);

            // 生成临时授权URL
            TemporarySignatureResponse response = obsClient.createTemporarySignature(request);

            return response.getSignedUrl();
        } finally {
            close(obsClient);
        }
    }

    /**
     * 下载文件流
     *
     * @param objectName 对象路径及名称
     * @return byte
     */
    @Override
    public byte[] downloadObjectStream(String objectName) throws IOException {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        try {
            ObsObject obsObject = obsClient.getObject(huaweiCloudObsConfig.getBucketName(), objectName);
            InputStream inputStream = obsObject.getObjectContent();
            // 返回文件流
            return IOUtils.toByteArray(inputStream);
        } finally {
            close(obsClient);
        }
    }

    /**
     * 删除文件
     *
     * @param objectName 对象路径及名称
     */
    @Override
    public void deleteObject(String objectName) {
        // 创建OBSClient实例。
        ObsClient obsClient = generateClient();

        // 删除文件或目录。如果要删除目录，目录必须为空。
        obsClient.deleteObject(huaweiCloudObsConfig.getBucketName(), objectName);

        // 关闭OBSClient
        close(obsClient);
    }

}
